/* 保留数组原有的特性，并且可以重写部分方法 */

// 创建一个对象，隐式原型指向形参 （类似es5的利用原型链的寄生组合式继承）
// newArrayObj.__proto__ = Array.prototype
// 在新newArrayObj添加方法不会影响原型上的方法，newArrayObj没有的方法才回去原型上找
const newArrayObj = Object.create(Array.prototype);

//找到所有的变异方法  concat slice 都不会改变原数组
const methods = [
  "push",
  "pop",
  "shift",
  "unshift",
  "reverse",
  "sort",
  "splice",
];

// 遍历变异的方法，对每一个进行重写，但内部还是调用原来的方法
// 也即：函数的劫持 切片编程
methods.forEach((method) => {
  // arr.push(1,2,3)
  // 重写了数组的方法
  newArrayObj[method] = function (...args) {
    //   内部调用原来的方法  (因为data的第一层数组做了响应式劫持，这边修改原数组的内容会被劫持到)
    //   newArrayObj.__proto__[method].apply(this, args);   this是arr
    const result = Object.getPrototypeOf(newArrayObj)[method].apply(this, args);

    //   我们需要对新增的数据再次进行劫持
    let inserted = [];
    //   __ob__是Observe实例，这里this是arr（也即数组属性的data）
    let ob = this.__ob__;
    switch (method) {
      case "push":
      case "unshift": // arr.unshift(1,2,3)
        inserted = args;
        break;
      case "splice": // arr.splice(0,1,{a:1},{b:1})
        inserted = args.slice(2);
        break;
      default:
        break;
    }
    console.log("新增的内容", inserted);
    if (inserted) {
      // 对新增的内容再次进行观测
      ob.observeArray(inserted);
    }

    ob.dep.notify(); // 数组变化了，通知对应的watcher更新

    return result;
  };
});

/* 
   导出新数组对象 
   将data中是数组的数据的原型指向 新数组对象 
   data.__proto__ = newArrayObj;
   当data中数组类型的数组调用变异的方法都会被监控到
   因为数组中没有就会在隐式原型中找，
   隐形原型即新数组对象，调用新数组对象中重写的变异方法，函数劫持，
   其实还是调用原来的数组的方法，完成对数据的操作
*/
export { newArrayObj };
